package com.axon.mvc.patterns.mediator
{
	import com.axon.base.helpers.AxFailure;
	import com.axon.base.helpers.AxReflectionUtils;
	import com.axon.base.managers.AxErrorManager;
	import com.axon.mvc.events.AxBroadcastEvent;
	import com.axon.mvc.events.AxCallControllerEvent;
	import com.axon.mvc.events.AxViewEvent;
	import com.axon.mvc.helpers.AxMvcUtils;
	import com.axon.mvc.patterns.facade.AxFacade;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	
	import org.puremvc.as3.interfaces.IMediator;
	import org.puremvc.as3.interfaces.INotification;
	import org.puremvc.as3.patterns.mediator.Mediator;

	public class AxMediator extends Mediator implements IMediator
	{
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		protected var fNotificationInterestList: Array = [];
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		public function AxMediator(viewComponent: DisplayObject, mediatorName: String = null)
		{
			if ( (!mediatorName) || (mediatorName == "") )
				mediatorName = AxReflectionUtils.getClassNameByInstance(this);
				
			super(mediatorName, viewComponent);
			
			if (viewComponent) 
				addEventListeners(viewComponent);

			initialize();
		}
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		override public function setViewComponent(viewComponent: Object): void
		{
			super.setViewComponent(viewComponent);
			addEventListeners(DisplayObject(viewComponent));
		}
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		public function addEventListeners(aView: DisplayObject): void
		{
			aView.addEventListener(Event.CLOSE,									onCloseEventFired);
			aView.addEventListener(AxViewEvent.VIEW_EVENT_FIRED,				onViewEventFired);
			aView.addEventListener(AxBroadcastEvent.BROADCAST_FIRED,			onBroadcastEventFired);
			aView.addEventListener(AxCallControllerEvent.CALL_CONTROLLER_FIRED,	onCallControllerEventFired);
		}

		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		public function get displayObject(): DisplayObject { return (viewComponent as DisplayObject) };
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		protected function initialize(): void { }  // Must be overriden;	
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		override public function listNotificationInterests(): Array { return fNotificationInterestList }	
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		protected function regResponseInterest(modelClass: Class, requestNames: Array): void 
		{
			if (modelClass) {
			
				var modelName: String = AxReflectionUtils.getClassNameByRef(modelClass);
				
				for each (var item1: String in requestNames) { 
					fNotificationInterestList.push(modelName + AxMvcUtils.removeAxVerbPrefix(item1) + AxMvcUtils.SUFIX_SUCCESS);
					fNotificationInterestList.push(modelName + AxMvcUtils.removeAxVerbPrefix(item1) + AxMvcUtils.SUFIX_FAILURE); } }
				 
			else {
				
				for each (var item2: String in requestNames) {
					fNotificationInterestList.push(item2 + AxMvcUtils.SUFIX_SUCCESS);
					fNotificationInterestList.push(item2 + AxMvcUtils.SUFIX_FAILURE); } 
			}
		}
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		protected function regBroadcastInterests(messages: Array): void
		{ 
			for each (var item: String in messages)
				fNotificationInterestList.push(item); 
		}
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		protected function broadcastMessage(message: String, body: Object, extraInfo: Object): void
		{
			(facade as AxFacade).broadcastMessage(this, message, body, extraInfo);
		}
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		protected function onViewEventFired(event: AxViewEvent): void
		{
			if (event.target == viewComponent)
			{
				var functionName: String = AxMvcUtils.PREFIX_EVENT + AxMvcUtils.removeAxVerbPrefix(event.name); 
			
				if (!this.hasOwnProperty(functionName))
					AxErrorManager.showFailure( new AxFailure(
					"Message for Software Engineers:\n\nHey guys, class " +
						AxReflectionUtils.getClassFullPathByInstance(this) + 
						" should implement method " + 
						functionName + 
						"(body: Object, extraInfo: Object) - View event handler.") );
				else
					callViewEventHandler(functionName, event);
			}
		}
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		protected function callViewEventHandler(functionName: String, event: AxViewEvent): void
		{
			if (event.body)
				this[functionName](event.body);
			else
				this[functionName]();
		}
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		protected function onBroadcastEventFired(event: AxBroadcastEvent): void
		{
			if (event.target == viewComponent)
				broadcastMessage(event.message, event.body, event.extraInfo);
		} 

		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		protected function onCallControllerEventFired(event: AxCallControllerEvent): void
		{
			if (event.target == viewComponent)
				callController(event.modelClass, event.action, event.body, event.extraInfo);
		} 
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		private function onCloseEventFired(event: Event): void
		{
			AppFacade(facade).unregMediator(this);
		}

		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		protected function callController(modelClass: Class, action: String, body: Object = null, extraInfo: Object = null): void
		{
			AxFacade(facade).callController( modelClass, action, body, extraInfo ); 
		}
		
		//////////////////////////////////////////////////////////////////////////////////////////////////////
		
		public override function handleNotification(notification: INotification): void
		{
			var name		: String =	notification.getName();
			
			var sender		: Object =	notification.getBody().hasOwnProperty(AxMvcUtils.TERM_SENDER) ?
										notification.getBody().sender :
										notification.getBody();
			
			var body		: Object =	notification.getBody().hasOwnProperty(AxMvcUtils.TERM_BODY) ?
										notification.getBody().body :
										notification.getBody();
			
			var extraInfo	: Object =	notification.getBody().hasOwnProperty(AxMvcUtils.TERM_EXTRA_INFO) ?
										notification.getBody().extraInfo :
										null;

			if ( AxMvcUtils.isNotificationResponse(name) )
			{
				var prefixName: String = AxMvcUtils.removeAxVerbPrefix( AxMvcUtils.getResponsePrefixName(name) );

				if ( !this.hasOwnProperty(AxMvcUtils.PREFIX_RESP + prefixName + AxMvcUtils.SUFIX_SUCCESS) &&
					 !this.hasOwnProperty(AxMvcUtils.PREFIX_RESP + prefixName + AxMvcUtils.SUFIX_FAILURE) )
				{
					AxErrorManager.showFailure( new AxFailure(
						"Message for Software Engineers:\n\nHey guys, class " +
						AxReflectionUtils.getClassFullPathByInstance(this) + 
						" should implement method " + 
						AxMvcUtils.PREFIX_RESP + prefixName + AxMvcUtils.SUFIX_SUCCESS + 
						"() and/or " + 
						AxMvcUtils.PREFIX_RESP + prefixName + AxMvcUtils.SUFIX_FAILURE + 
						"(sender: Object, body: Object, extraInfo: Object) - Request response handler(s).") );
					
					return;
				}
				
				if (this.hasOwnProperty(AxMvcUtils.PREFIX_RESP + AxMvcUtils.removeAxVerbPrefix(name)))
					this[AxMvcUtils.PREFIX_RESP + AxMvcUtils.removeAxVerbPrefix(name)](sender, body, extraInfo);
			} 
			else if (!this.hasOwnProperty(AxMvcUtils.PREFIX_BRCAST + AxMvcUtils.removeAxVerbPrefix(name)))
			{
				AxErrorManager.showFailure( new AxFailure(
					"Message for Software Engineers:\n\nHey guys, class " +
					AxReflectionUtils.getClassFullPathByInstance(this) + 
					" should implement method " + 
					AxMvcUtils.PREFIX_BRCAST + AxMvcUtils.removeAxVerbPrefix(name) + 
					"(sender: Object, body: Object, extraInfo: Object) - Message broadcast handler.") );
			}
			else
			{
				this[AxMvcUtils.PREFIX_BRCAST + AxMvcUtils.removeAxVerbPrefix(name)](sender, body, extraInfo);
			}
		}		
		
	}
}